using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;

namespace AvalonAdmin.BaseViewModel
{
    /// <summary>
    /// 选择功能视图模型实现
    /// </summary>
    /// <typeparam name="T">数据类型</typeparam>
    public class SelectionViewModel<T> : ISelectionViewModel<T>
    {
        #region 字段
        private bool _isAllSelected;
        private readonly ObservableCollection<T> _data;
        private readonly Func<T, bool> _getIsSelected;
        private readonly Action<T, bool> _setIsSelected;
        #endregion

        #region 构造函数
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="data">数据集合</param>
        /// <param name="getIsSelected">获取选中状态的委托</param>
        /// <param name="setIsSelected">设置选中状态的委托</param>
        public SelectionViewModel(ObservableCollection<T> data, 
            Func<T, bool> getIsSelected, 
            Action<T, bool> setIsSelected)
        {
            _data = data ?? throw new ArgumentNullException(nameof(data));
            _getIsSelected = getIsSelected ?? throw new ArgumentNullException(nameof(getIsSelected));
            _setIsSelected = setIsSelected ?? throw new ArgumentNullException(nameof(setIsSelected));
        }
        #endregion

        #region 属性
        /// <summary>
        /// 是否全选
        /// </summary>
        public bool IsAllSelected
        {
            get => _isAllSelected;
            set => SetProperty(ref _isAllSelected, value);
        }

        /// <summary>
        /// 是否有选中项
        /// </summary>
        public bool HasSelectedItems => _data.Any(_getIsSelected);
        #endregion

        #region 方法
        /// <summary>
        /// 获取选中的项目
        /// </summary>
        /// <returns></returns>
        public List<T> GetSelectedItems()
        {
            return _data.Where(_getIsSelected).ToList();
        }

        /// <summary>
        /// 全选/取消全选
        /// </summary>
        public void ToggleSelectAll()
        {
            bool hasUnselected = _data.Any(item => !_getIsSelected(item));

            foreach (var item in _data)
            {
                _setIsSelected(item, hasUnselected);
            }

            UpdateAllSelectedState();
            OnPropertyChanged(nameof(HasSelectedItems));
        }

        /// <summary>
        /// 选中项目
        /// </summary>
        /// <param name="item">项目</param>
        public void SelectItem(T item)
        {
            if (item != null)
            {
                bool currentState = _getIsSelected(item);
                _setIsSelected(item, !currentState);
                UpdateAllSelectedState();
                OnPropertyChanged(nameof(HasSelectedItems));
            }
        }

        /// <summary>
        /// 更新全选状态
        /// </summary>
        public void UpdateAllSelectedState()
        {
            if (_data.Count == 0)
            {
                IsAllSelected = false;
            }
            else
            {
                IsAllSelected = _data.All(_getIsSelected);
            }
        }
        #endregion

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        protected bool SetProperty<TValue>(ref TValue field, TValue value, [CallerMemberName] string? propertyName = null)
        {
            if (Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }
        #endregion
    }
}